import { DocumentEventCenter as DocumentEventCenter } from "../base_frame/DocumentEventCenter";
import { IShaderBase } from "../base_frame/IShaderBase";
import { Keyboard } from "../base_frame/Keyboard";
import { ShaderBase } from "../base_frame/ShaderBase";
import { Vector3 } from "../base_frame/math/Vector3";

export class CameraEmulator extends ShaderBase implements IShaderBase {

    inputBlur(text: string): void {
    }

    protected readonly VS: string =
        "attribute vec4 a_Position;\n" +
        "attribute vec4 a_Color;\n" +
        "uniform mat4 u_ViewMatrix;\n" +
        "varying vec4 v_Color;\n" +
        "void main(){\n" +
        "   v_Color = a_Color;\n" +
        "   gl_Position = u_ViewMatrix * a_Position;\n" +
        "}\n";

    protected readonly FS: string =
        "precision mediump float;\n" +
        "varying vec4 v_Color;\n" +
        "void main(){\n" +
        "   gl_FragColor = v_Color;\n" +
        "}\n";

    protected a_Position: number;
    protected a_Color: number;
    protected u_ViewMatrix: WebGLUniformLocation;

    protected _viewMatrix: Matrix4;
    protected _eyeVec3: Vector3;

    protected _moduleMatrix:Matrix4;
    protected _angle: number = 0;;

    init(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        if (!initShaders(gl, this.VS, this.FS)) return console.error("init shader fail");
        this._eyeVec3 = new Vector3(0.0, 0.2, 0.25);
        this._moduleMatrix = new Matrix4();
        this._initShaderReference(gl);
        this._initShaderValue(gl);
        this._initShaderBuffer(gl);
        this.draw(gl);
        DocumentEventCenter.regKeyDown(this, this.onKeyDown, [gl]);
    }

    protected _initShaderValue(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        let viewMatrix = this._viewMatrix ||= new Matrix4();
        let zero = Vector3.ZERO;
        let up = Vector3.Up;
        let eye = this._eyeVec3;
        viewMatrix.setLookAt(
            eye.x, eye.y, eye.z,
            zero.x, zero.y, zero.z,
            up.x, up.y, up.z);
        this._viewMatrix = viewMatrix;
        this._viewMatrix.multiply(this._moduleMatrix);
        gl.uniformMatrix4fv(this.u_ViewMatrix, false, viewMatrix.elements);
    }

    protected _initShaderReference(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        // @ts-ignore
        let program = gl.program;
        this.a_Position = gl.getAttribLocation(program, "a_Position");
        this.a_Color = gl.getAttribLocation(program, "a_Color");
        this.u_ViewMatrix = gl.getUniformLocation(program, "u_ViewMatrix");

    }

    protected _initShaderBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        let vertexBuffer = gl.createBuffer();
        let colorBuffer = gl.createBuffer();
        if (!vertexBuffer || !colorBuffer) return console.error("init buffer fail");

        let vertexColorArr = new Float32Array([
            -0.4, 0.5, 0.2, 1.0, 0.4, 0.4,
            -0.4, -0.5, 0.2, 0.4, 0.4, 0.4,
            0.4, 0.1, 0.2, 1.0, 0.4, 0.4,

            -0.2, 0.5, 0.2, 0.4, 0.4, 0.4,
            -0.2, -0.5, 0.2, 0.4, 1.0, 0.4,
            0.6, 0.1, 0.2, 0.4, 0.4, 0.4,

            0.0, 0.5, 0.2, 0.4, 0.4, 0.4,
            0.0, -0.5, 0.2, 0.4, 0.4, 1.0,
            0.8, 0.1, 0.2, 0.4, 0.4, 0.4,
        ]);

        let size = vertexColorArr.BYTES_PER_ELEMENT;
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertexColorArr, gl.STREAM_DRAW);
        gl.vertexAttribPointer(this.a_Position, 3, gl.FLOAT, false, size * 6, 0);
        gl.enableVertexAttribArray(this.a_Position);

        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vertexColorArr, gl.STATIC_DRAW);
        gl.vertexAttribPointer(this.a_Color, 3, gl.FLOAT, false, size * 6, size * 3);
        gl.enableVertexAttribArray(this.a_Color);
    }

    onKeyDown(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: KeyboardEvent) {
        if (ev.keyCode == Keyboard.A) {
            this._eyeVec3.x -= 0.1;
        }
        if (ev.keyCode == Keyboard.D) {
            this._eyeVec3.x += 0.1;

        }
        if (ev.keyCode == Keyboard.W) {
            this._eyeVec3.y += 0.1;
        }
        if (ev.keyCode == Keyboard.S) {
            this._eyeVec3.y -= 0.1;
        }
        if (ev.keyCode == Keyboard.R) {
            this._eyeVec3.y = 0.2;
            this._eyeVec3.x = 0.2;
        }
        if(ev.keyCode == Keyboard.P){
            this._angle += 10;
            this._moduleMatrix.setRotate(this._angle, 0,0,1);
        }
        this._initShaderValue(gl);
        this.draw(gl);
    }

    draw(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, 9);
    }

}